package com.tyylab.kestrel.framework.spring.rpc.feign.impl;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.This;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;

/**
 * Enhanced Feign Fallback Interceptor with detailed logging and context information
 * @author tyylab
 */
@Slf4j
public class EnhancedFeignFallbackInterceptor {
    
    private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    @RuntimeType
    public static Object intercept(@Origin Method method, @This Object feignImpl, @AllArguments Object[] arguments) {
        String timestamp = LocalDateTime.now().format(TIMESTAMP_FORMATTER);
        String methodName = method.getName();
        String className = method.getDeclaringClass().getSimpleName();
        String fullMethodName = method.getDeclaringClass().getName() + "." + methodName;
        
        // Log detailed error information
        log.error("=== Feign Fallback Triggered ===");
        log.error("Timestamp: {}", timestamp);
        log.error("Service: {}", className);
        log.error("Method: {}", methodName);
        log.error("Full Method: {}", fullMethodName);
        log.error("Arguments: {}", Arrays.toString(arguments));
        log.error("Return Type: {}", method.getReturnType().getName());
        log.error("Fallback Reason: Feign call failed or service unavailable");
        log.error("================================");
        
        // Get default value based on return type
        Object defaultValue = getDefaultValue(method.getReturnType());
        
        log.info("Fallback returning default value: {} for method: {}", defaultValue, methodName);
        
        return defaultValue;
    }
    
    /**
     * Get default value for different return types with enhanced support
     * @param returnType the return type of the method
     * @return default value
     */
    private static Object getDefaultValue(Class<?> returnType) {
        if (returnType == void.class || returnType == Void.class) {
            return null;
        } else if (returnType == boolean.class || returnType == Boolean.class) {
            return false;
        } else if (returnType == char.class || returnType == Character.class) {
            return '\0';
        } else if (returnType == byte.class || returnType == Byte.class) {
            return (byte) 0;
        } else if (returnType == short.class || returnType == Short.class) {
            return (short) 0;
        } else if (returnType == int.class || returnType == Integer.class) {
            return 0;
        } else if (returnType == long.class || returnType == Long.class) {
            return 0L;
        } else if (returnType == float.class || returnType == Float.class) {
            return 0.0f;
        } else if (returnType == double.class || returnType == Double.class) {
            return 0.0;
        } else if (returnType == String.class) {
            return "";
        } else if (returnType.isArray()) {
            return java.lang.reflect.Array.newInstance(returnType.getComponentType(), 0);
        } else if (returnType.isEnum()) {
            // Return first enum value as default
            Object[] enumConstants = returnType.getEnumConstants();
            return enumConstants != null && enumConstants.length > 0 ? enumConstants[0] : null;
        } else {
            // For complex objects, return null
            return null;
        }
    }
} 